package com.netvine.iias;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@RestController
public class Controller {
    private static final Logger log = LoggerFactory.getLogger(Controller.class);
    @Value("${nvr.server}")
    private String server;

    @Value("${nvr.secret}")
    private String secret;

    @Value("${nvr.type}")
    private String type;

    @Value("${nvr.ip}")
    private String ip;

    @Value("${nvr.port}")
    private Integer port;

    @Value("${nvr.account}")
    private String account;

    @Value("${nvr.password}")
    private String password;

    @Autowired
    private run run;

    @Autowired
    SdkServiceFactoryBean sdkServiceFactoryBean;

    private static ObjectMapper objectMapper = new ObjectMapper();

    private static LinkedList<String> CHANNEL_LIST = new LinkedList<>();

    private static String LAST_CHANNEL = "";
    private static String LAST_RTSP = "";
    private static String LAST_WS = "";

    //云台转动
    @PostMapping("/videoAnalytics/deviceControl/camera/rotate")
    public Result rotate(@RequestBody PtzDto ptzDto) {
        ptzDto.setChanNum(ptzDto.getDeviceId());
        try {
            sdkServiceFactoryBean.setType(type);
            SDKservice sdKservice = sdkServiceFactoryBean.getObject();
            sdKservice.PTZControl(ptzDto);
        } catch (Exception e) {
            log.error("e:", e);
            return Result.error("操作失败，请稍后重试");
        }
        return Result.ok();
    }

    //放大缩小
    @PostMapping("/videoAnalytics/deviceControl/camera/zoom")
    public Result zoom(@RequestBody PtzDto ptzDto) {
        ptzDto.setChanNum(ptzDto.getDeviceId());
        try {
            sdkServiceFactoryBean.setType(type);
            SDKservice sdKservice = sdkServiceFactoryBean.getObject();
            sdKservice.zoomControl(ptzDto);
        } catch (Exception e) {
            log.error("e:", e);
            return Result.error("操作失败，请稍后重试");
        }
        return Result.ok();
    }

    //放大缩小
    @PostMapping("/videoAnalytics/deviceControl/camera/preset")
    public Result preset(@RequestBody PtzDto ptzDto) {
        ptzDto.setChanNum(ptzDto.getDeviceId());
        try {
            sdkServiceFactoryBean.setType(type);
            SDKservice sdKservice = sdkServiceFactoryBean.getObject();
            sdKservice.presetPoint(ptzDto);
        } catch (Exception e) {
            log.error("e:", e);
            return Result.error("操作失败，请稍后重试");
        }
        return Result.ok();
    }

    //放大缩小
    @PostMapping("/videoAnalytics/deviceControl/camera/reset")
    public Result reset(@RequestBody PtzDto ptzDto) {
        ptzDto.setChanNum(ptzDto.getDeviceId());
        try {
            sdkServiceFactoryBean.setType(type);
            SDKservice sdKservice = sdkServiceFactoryBean.getObject();
            sdKservice.presetPoint(ptzDto);
        } catch (Exception e) {
            log.error("e:", e);
            return Result.error("操作失败，请稍后重试");
        }
        return Result.ok();
    }

    @GetMapping("/video")
    public Result getVideoUrl(@RequestParam String rtsp) {
        //run.initChannel(chanNum);
//        log.info("chanNum is:{}", chanNum);
//        if (LAST_CHANNEL != "") {
//            stopPushStream(LAST_CHANNEL);
//            CHANNEL_LIST.add(LAST_CHANNEL);
//        }
        String s1 = String.valueOf(CHANNEL_LIST.poll());
        LAST_CHANNEL = s1;
        Base64.Encoder encoder = Base64.getEncoder();
        String[] split = rtsp.split("/");
        String[] split1 = split[2].split(":");
        String[] split2 = split1[1].split("@");
        String rest = "";
        for (int i = 3; i < split.length; i++) {
            rest += "/";
            rest += split[i];
        }
        rtsp = "rtsp://" + split2[1] + rest;
        if (type.equals("dh")) {
            rtsp += "&subtype=0";
        }
        byte[] encoded = encoder.encode(rtsp.getBytes());
        setPushStreamAddress(new String(encoded), server, s1, password, account);
        String s = startPushStream(server, s1);
        LAST_WS = s;
        return Result.ok(s);
    }

    @GetMapping("/close")
    public Result closeVideo(@RequestParam String channel) {
        stopPushStream(channel);
        CHANNEL_LIST.add(channel);
        return Result.ok();
    }

    @GetMapping("/list")
    public Result getList() {
        List<CameraInfo> cameraList = null;
        try {
            sdkServiceFactoryBean.setType(type);
            SDKservice sdKservice = sdkServiceFactoryBean.getObject();
            cameraList = sdKservice.getCameraList();
        } catch (Exception e) {
            log.error("e:", e);
            return Result.error("操作失败，请稍后重试");
        }
        return Result.ok(cameraList);
    }

//    @PostMapping("/camera/preview")
//    public Result controllPtz(@RequestBody PtzDto ptzDto) {
//        return run.changeCameraStatus(ptzDto.getPosition(), ptzDto.getIsStop(), ptzDto.getSpeed(), ptzDto.getChanNum());
//    }

//    @PostMapping("/camera/zoom")
//    public Result changeZoom(@RequestBody PtzDto ptzDto) {
//        return run.changeZoom(ptzDto.getxTop(), ptzDto.getxBottom(), ptzDto.getyTop(), ptzDto.getyBottom(), ptzDto.getChanNum());
//    }

//    @GetMapping("/camera/preset")
//    public Result preset() {
//        return run.setPos();
//    }
//
//    @GetMapping("/camera/goto")
//    public Result gotoPos() {
//        return run.gotoPos();
//    }

    @GetMapping("/camera/pos/list")
    public Result getPosList(@RequestParam Integer chanNum) {
        return run.getPosList(chanNum);
    }

    @GetMapping("/stop")
    public Result stop() {
        return run.stop();
    }

    @PostConstruct
    public void init() {
        for (int i = 33; i < 100; i++) {
            CHANNEL_LIST.add(String.valueOf(i));
        }
    }

    public String generateUrl(Map<String, String> params, String baseUrl) {
        // Add timestamp 't'
        params.put("t", String.valueOf(System.currentTimeMillis() / 1000));

        // Convert map to list of entries and sort by key
        List<Map.Entry<String, String>> sortedParams = new ArrayList<>(params.entrySet());
        sortedParams.add(new AbstractMap.SimpleEntry<>("secret", secret));
        sortedParams.sort(Comparator.comparing(Map.Entry::getKey));

        StringBuilder str = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams) {
            String key = entry.getKey();
            String value = entry.getValue();
            if ("token".equals(key)) {
                continue;
            }
            if (str.length() > 0) {
                str.append("&");
            }
            if ("secret".equals(key)) {
                str.append(key).append("=").append(value);
            } else {
                str.append(key).append("=").append(value);
            }
        }

        // Calculate MD5 hash
        String md5 = calculateMD5(str.toString());
        params.put("token", md5);

        // Construct URL
        StringBuilder url = new StringBuilder(baseUrl);
        url.append("?");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if ("token".equals(key)) {
                continue;
            }
            url.append(key).append("=").append(value).append("&");
        }
        url.append("token=").append(md5);

        return url.toString();
    }

    private static String calculateMD5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : messageDigest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 Algorithm not found", e);
        }
    }

    private void setPushStreamAddress(String rtsp, String server, String channel, String password, String account) {
        HashMap<String, String> params = new HashMap<>();
        params.put("command", "set_live_rtsp");
        params.put("value", rtsp);
        params.put("channel", channel);
        params.put("user", account);
        params.put("pass", password);

        String baseUrl = "http://" + server + "/xsw/control";
        String reqUrl = generateUrl(params, baseUrl);
        System.out.println("reqUrl: " + reqUrl);
        String post = HttpUtil.post(reqUrl, new HashMap<>());
        System.out.println(post);
    }

    private String startPushStream(String server, String channel) {
        HashMap<String, String> params = new HashMap<>();
        params.put("command", "rtsp_enable_control");
        params.put("value", "start");
        params.put("channel", channel);

        String baseUrl = "http://" + server + ":80/xsw/control";
        String reqUrl = generateUrl(params, baseUrl);
        System.out.println("reqUrl: " + reqUrl);
        String post = HttpUtil.post(reqUrl, new HashMap<>());
        System.out.println(post);

        return "http://" + server + ":80/hdl/hlsram/live" + channel + ".flv";
    }

    private void stopPushStream(String channel) {
        HashMap<String, String> params = new HashMap<>();
        params.put("command", "rtsp_enable_control");
        params.put("value", "stop");
        params.put("channel", channel);

        String baseUrl = "http://" + server + "/xsw/control";
        String reqUrl = generateUrl(params, baseUrl);
        System.out.println("reqUrl: " + reqUrl);
        String post = HttpUtil.post(reqUrl, new HashMap<>());
    }
}
